#include "include/proc.h"
#include "include/type.h"
#include "include/kconst.h"
#include "include/global.h"
#include "include/klib.h"
#include "include/printf.h"
#include "include/syscall.h"
#include "include/misc.h"
int ldt_seg_linear(PROCESS *p, int idx)
{
    DESCRIPTOR *d = &p->ldts[idx];
    return d->base_high << 24 | d->base_mid | d->base_low;
}

void* va2la(int pid, void *va)
{
    PROCESS *p = &proc_table[pid];

    u32 seg_base = ldt_seg_linear(p, INDEX_LDT_RW);
    u32 la = seg_base + (u32) va;
    if (pid < NR_TASKS + NR_PROC)
    {
        assert(la == (u32) va);
    }
    return (void*) va;
}

void schedule()
{
    struct s_proc *p = p_proc_ready;
    int i = PROC_SZ;
    while (i)
    {
        p++;
        if (p >= proc_table + PROC_SZ)
            p = proc_table;
        if (p->p_flags == 0) {
            p_proc_ready = p;
            break;
        }
        --i;
    }
    
}

void reset_msg(MESSAGE *p)
{
    memset(p, 0, sizeof(MESSAGE));
}

void block(struct s_proc *p)
{
    assert(p->p_flags);
    //TODO
}

void unblock(struct s_proc *p)
{
    if (p->p_flags != 0)
        printf("p->p_flags=%d", p->p_flags);
    assert(p->p_flags == 0);
}

static int deadlock(int src, int dest)
{
    struct s_proc* p = proc_table + dest;
    while (1)
    {
        if (p->p_flags & SENDING)
        {
            if (p->p_sendto == src)
            {
                p = proc_table + dest;
                printf("=_=%s", p->p_name);
                do 
                {
                    assert(p->p_msg);
                    p = proc_table + p->p_sendto;
                    printf("->%s", p->p_name);
                } while (p != proc_table + src);
                printf("=_=");
                return 1;
            }
            p = proc_table + p->p_sendto;
        }
        else 
        {
            break;
        }
    }
    return 0;
}

int msg_send(struct s_proc *current, int dest, MESSAGE *m)
{
    struct s_proc *sender = current;
    u32 sender_pid = proc2pid(sender);
    struct s_proc *p_dest = proc_table + dest;
    
    assert(sender_pid != dest);
    
    if (deadlock(sender_pid, dest))
    {
        panic(">> DEAD LOCK <<");
    }
    if ((p_dest->p_flags & RECEIVING) &&
        (p_dest->p_recvfrom == sender_pid || 
        p_dest->p_recvfrom == ANY))
    {
        assert(p_dest->p_msg);
        assert(m);
        phys_copy(va2la(dest, p_dest->p_msg),
                  va2la(sender_pid, m),
                  sizeof(MESSAGE));
        
        p_dest->p_msg = 0;
        p_dest->p_flags &= ~RECEIVING;
        p_dest->p_recvfrom = NO_TASK;
        unblock(p_dest);

    }
    else
    {
        sender->p_flags |= SENDING;
        assert(sender->p_flags == SENDING);
        sender->p_sendto = dest;
        sender->p_msg = m;

        /*放置到接受者的队列中*/
        struct s_proc* p;
        if (p_dest->q_sending)
        {
            p = p_dest->q_sending;
            while (p->next_sending)
                p = p->next_sending;
            p->next_sending = sender;
        }
        else
        {
            p_dest->q_sending = sender;
        }
        sender->next_sending = 0;
        block(sender);
        assert(sender->p_flags == SENDING);
        assert(sender->p_msg != 0);
        assert(sender->p_recvfrom == NO_TASK);
        assert(sender->p_sendto == dest);
        schedule(); //如该不进行调度的话，没法达到阻塞的效果
    }
    return 0;

}

int msg_receive(struct s_proc *current, int src, MESSAGE *m)
{
    struct s_proc *p_who_wanna_recv = current;
    struct s_proc *p_from = 0;
    struct s_proc *prev = 0;
    int copyok = 0;
    if ((p_who_wanna_recv->has_int_msg) &&
        ((src == ANY) || (src == INTERRUPT)))
    {
        MESSAGE msg;
        reset_msg(&msg);
        msg.source = INTERRUPT;
        msg.type = HARD_INT;
        assert(m);
        phys_copy(va2la(proc2pid(p_who_wanna_recv), m), &msg, sizeof(MESSAGE));
        p_who_wanna_recv->has_int_msg = 0;
        assert(p_who_wanna_recv->p_flags == 0);
        assert(p_who_wanna_recv->p_msg == 0);
        assert(p_who_wanna_recv->p_sendto == NO_TASK);
        assert(p_who_wanna_recv->has_int_msg == 0);
        return 0;
    }
    if (src == ANY)
    {
        if (p_who_wanna_recv->q_sending)
        {
            p_from = p_who_wanna_recv->q_sending;
            copyok = 1;
        }
    }
    else if (src >= 0 && src < NR_TASKS + NR_PROC)
    {
        p_from = &proc_table[src];
        if ((p_from->p_flags & SENDING) && (p_from->p_sendto == proc2pid(p_who_wanna_recv)))
        {
            copyok = 1;
            struct s_proc *p = p_who_wanna_recv->q_sending;
            assert(p);
            while (p)
            {
                assert(p_from->p_flags & SENDING);
                if (proc2pid(p) == src)
                {
                    break;
                }
                prev = p;   //只是为了找到prev方便后续把p_from移除
                p = p->next_sending;
            }
        }
        
    }
    if (copyok)
    {
       
        if (p_from == p_who_wanna_recv->q_sending)
        {
            
            assert(prev == 0);
            p_who_wanna_recv->q_sending = p_from->next_sending;
            p_from->next_sending = 0;
        }
        else
        {
            
            assert(prev);
            prev->next_sending = p_from->next_sending;
            p_from->next_sending = 0;
        }
        
        assert(m);
		assert(p_from->p_msg);
        
        phys_copy(va2la(proc2pid(p_who_wanna_recv), m),
			  va2la(proc2pid(p_from), p_from->p_msg),
			  sizeof(MESSAGE));
        
        p_from->p_msg = 0;
        p_from->p_sendto = NO_TASK;
        p_from->p_flags &= ~SENDING;
        unblock(p_from);
    }
    else
    {
        
        p_who_wanna_recv->p_flags |= RECEIVING;
        p_who_wanna_recv->p_msg = m;
        p_who_wanna_recv->p_recvfrom = src;
        block(p_who_wanna_recv);
        assert(p_who_wanna_recv->p_flags == RECEIVING);
		assert(p_who_wanna_recv->p_msg != 0);
		assert(p_who_wanna_recv->p_recvfrom != NO_TASK);
		assert(p_who_wanna_recv->p_sendto == NO_TASK);
		assert(p_who_wanna_recv->has_int_msg == 0);
        schedule(); //如该不进行调度的话，没法达到阻塞的效果
    }
    return 0;
}


int send_recv(int function, int src_dest,MESSAGE *msg)
{
    int ret=0;
    if (function == RECEIVE)
        memset(msg, 0, sizeof(MESSAGE));
    switch (function)
    {
    case BOTH:
        ret = sendrec(SEND, src_dest, msg);
        
        if (ret == 0)
            ret = sendrec(RECEIVE, src_dest, msg);
        break;
    case SEND:
    case RECEIVE:
        ret = sendrec(function, src_dest, msg);
    default:
        break;
    }
    return ret;
}

/*发出中断通知 */
void inform_int(int task_nr)
{
    struct s_proc *p = proc_table + task_nr;
    if ((p->p_flags & RECEIVING) && ((p->p_recvfrom == INTERRUPT) || (p-> p_recvfrom == ANY)))
    {
        p->p_msg->source = INTERRUPT;
        p->p_msg->type = HARD_INT;
        p->p_msg = 0;
        p->has_int_msg = 0;
        p->p_flags &= ~RECEIVING;
        p->p_recvfrom = NO_TASK;
        assert(p->p_flags == 0);
        unblock(p);
        assert(p->p_flags == 0);
		assert(p->p_msg == 0);
		assert(p->p_recvfrom == NO_TASK);
		assert(p->p_sendto == NO_TASK);
    }
    else 
    {
        p->has_int_msg = 1;
    }
}